//<%@ taglib prefix="jj" uri="http://jaxson.org/base" %>

//<jj:import>
org.jaxson.util.collections.List;
org.jaxson.util.collections.Map;
//org.jaxson.util.http.XHR;
org.jaxson.util.http.ReverseAjaxBus;
//</jj:import>

//<jj:struct className="org.jaxson.struts.logging.ClientLogBatch" alias="ClientLogBatch"/>
//<jj:struct className="org.jaxson.struts.logging.JavascriptLogEntry" alias="LogEntry"/>
//<jj:struct className="org.jaxson.struts.logging.LogConfigurationEvent" alias="LogConfiguration"/>

/**
 * LogManager
 */
LogManager = new function()
{
	var loggers = new org.jaxson.util.collections.Map();
	var debugEl = null;
	
	function configure( logger, event ){
		
		if( event.enableRemote !== null ){
			logger.setRemoteLoggingEnabled( event.enableRemote );
		}
		
		if( event.level !== 0 ){
			logger.setLogLevel( event.level );
		}
		
		if( event.batchSize ){
			logger.setRemoteBatchSize(event.batchSize);
		}
	}
	
	var handleRemoteConfiguration = function( event ){
		
		// apply settings to all loggers
		if( event.applyGlobally === true ){
			var keys = loggers.keys();
			
			for( i=0; i<keys.size(); i++ ){
				configure( loggers.get(keys.get(i)), event );
			}
		}
		// apply settings to a single logger
		else{
			logger = loggers.get( event.loggerName );
			
			if( logger === null )
				return;
			
			configure( logger, event );
		}
	};
	
	var ra = org.jaxson.util.http.ReverseAjaxBus;
	ra.subscribe( "<%= org.jaxson.struts.logging.LogConfigurationEvent.EVENT_NAME %>", handleRemoteConfiguration );
	
	var that = {
		addLogger : function( logger ){
			loggers.put( logger.getName(), logger );
		},

		setRemoteLoggingEnabled : function( loggerName, flag ){
			var logger = loggers.get( loggerName );
			
			if( logger != null ){
				logger.setRemoteLoggingEnabled( flag );
			}
		},
		
		setDefaultDebugEl : function( elId ){
			debugEl = Query.getElementById( elId );
		},
		
		getDefaultDebugEl : function(){
			return debugEl;
		}
	};
	
	return that;
};

/**
 * Logging object.
 */
Logger = function( name, level, debugElId ){
		
	if( name === null || name === undefined || level === null || level === undefined )
		throw "InstantiationException: Loggers must be supplied a name and log level.";
		
	var remoteMessages = new org.jaxson.util.collections.List();
	
	//var debugId = debugElId === undefined || debugElId === null?"debug":debugElId;
	var debugEl = null;	
	
	if( debugElId !== undefined && debugElId !== null ){
		debugEl = Query.getElementById( debugElId );
	}
	else if( LogManager.getDefaultDebugEl() !== null && LogManager.getDefaultDebugEl() !== undefined ){
		debugEl = LogManager.getDefaultDebugEl();
	}
	
	var that = null;
	var logEl = null;
	
	// application level configs
	var remoteLoggingEnabled = ApplicationConfiguration.getProperty("client.logger.remote" );
	var remoteMessageBatchSize = ApplicationConfiguration.getProperty("client.logger.remote.batch.size");
	var url = ApplicationConfiguration.getProperty("client.logger.url");
	
	function sendBatch( remoteMessages ){
		var msg = "";
		var msgs = remoteMessages.asArray();
		var batch = new ClientLogBatch(msgs);
		
		var transport = new org.jaxson.util.http.XHR();
		var localXHRLogger = new Logger( "local XHR logger", Logger.LEVEL_TRACE );
		localXHRLogger.setRemoteLoggingEnabled( false );
		transport.setLogger( localXHRLogger );
		transport.setRequestParameters( {messages: JSON.stringify(batch)} );
		transport.setMethod( "POST" );
		transport.doRequest( url );
	}
	
	function isFF(){
		return navigator.userAgent.indexOf( "Firefox" ) != -1 && window["console"] !== undefined;
	}
	
	function formatLogMessage(){
		return new Date() + "\t" + name + "\t" + msg;
	}
	
	function doDir( obj ){
		if( window["console"] ){
			if(console["info"])
				console.info( "dumping ", obj, " in ", name );
			if(console["dir"])
				console.dir( obj );
		}
		
		// recursive iterate through object graph.  arg.
	}
	
	function println( args, llevel, instance ){
		
		var msg = ": ";
		
		for( i=0; i<args.length; i++ ){
			if( args[i] )
				msg += args[i] + "\t";
		}
		
		if( msg instanceof Error ){
			e = msg;
			msg = e + ":" + e.message;
		}
		
		if( that == null )
			that = instance;
		
		if( llevel < level )
			return;
		
		// try to load the debug element.
		if( debugEl !== null && Query.getElementById( 'debugLog' ) === null ){
			//debugEl = document.getElementById( debugId );
			//if( debugEl !== undefined && debugEl !== null )
			{
				debugEl.innerHTML = "<table width='100%'>" + 
									"<thead style='position: fixed;'><tr>" + 
									"<th align='left'>date</th>" + 
									"<th align='left'>category</th>" + 
									" <th align='left'>message</th>" + 
									"</tr></thead>" + 
									"<tbody id='debugLog' style='overflow: scroll'></tbody></table>";
									
				logEl = document.getElementById( 'debugLog' );
			}
		}
		
		// no debug element, but firebug is installed.
		if( window["console"] !== undefined ){
			
			switch( llevel ){
				case Logger.LEVEL_TRACE:
				if(console["debug"])
					console.debug( args );
				break;
			
				case Logger.LEVEL_DEBUG:
				if(console["debug"])
					console.debug( name + "::DEBUG", args );
				break;
				
				case Logger.LEVEL_INFO:
				if(console["info"])
					console.info( name + "::INFO", args );
				break;
				
				case Logger.LEVEL_WARN:
				if(console["warn"])
					console.warn( name + "::WARN", args );
				break;
				
				case Logger.LEVEL_ERROR:
				if(console["error"])
					console.error( name + "::ERROR", args );
				break;
			}
		}

		// Not firefox and debug el exists... if the debug element exists, append.
		else if( debugEl !== null) {
			
			// ie hack.
			var func = function(){
				if( logEl === null )
					return;
				
				var foo = logEl.insertRow(0);
				foo.insertCell( 0 ).innerHTML = new Date();
				foo.insertCell( 1 ).innerHTML = name;
				foo.insertCell( 2 ).innerHTML = msg;
				debugEl.scrollTop = 100000; // TODO: fix the scroll position to set correctly automagically.
			};
			
			setTimeout( func, 100 );
		}
		
		// remote logging enabled
		if( remoteLoggingEnabled ){
			
			remoteMessages.add( LogEntry( msg, name, level, new Date().getTime() ) );
			
			if( remoteMessages.size() >= remoteMessageBatchSize ){
				sendBatch( remoteMessages );
				remoteMessages.clear();
			}
		}
	}
	
	that = {
		dump : function( obj ){
			doDir( obj );
		},
			
		trace : function(){
			println( arguments, Logger.LEVEL_TRACE, this );
		}, 
	
		debug: function(){
			println( arguments, Logger.LEVEL_DEBUG, this );
		},
		
		info: function(){
			println( arguments, Logger.LEVEL_INFO, this );
		},
		
		warn: function(){
			println( arguments, Logger.LEVEL_WARN, this );
		},
		
		error: function(){
			println( arguments, Logger.LEVEL_ERROR, this );
		},
		
		setRemoteLoggingEnabled: function( flag ){
			remoteLoggingEnabled = flag;
			println( "remote logging " + (flag?"enabled":"disabled") + " in logger " + name, Logger.LEVEL_WARN, this );
		},
		
		setRemoteBatchSize: function( size ){
			remoteMessageBatchSize = size;
		},
		
		setDebugId : function( debugId ){
			that.debugId = debugId;
		},
		
		getDebugId : function(){
			return that.debugId;
		},
		
		clear : function(){
			debugEl.innerHtml = ""; 
		},
		
		setLogLevel : function( level ){
			that.level = level;
		},
		
		getLogLevel : function(){
			return that.level;
		},
		
		setUrl : function( u ){
			return url = u;
		},
		
		getUrl : function(){
			return url;
		},
		
		getName : function(){
			return name;
		}
	};
	
	LogManager.addLogger( that );
	
	return that;
};

//<%
out.println(org.jaxson.struts.logging.LogLevel.asJavascript());
//%>

ReverseAjaxBus.setLogger( new Logger( "org.jaxson.util.http.ReverseAjaxBus", Logger.LEVEL_DEBUG ) );
delete ReverseAjaxBus.setLogger;
